"""
    功能：Z评分模型
    作者：hwang_zhicheng
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

# 读取上市公司数据
# data_xls_1 = pd.read_excel("白酒上市公司交易额表.xls")
# data_xls_2 = pd.read_excel("白酒上市公司营收.xls")
data_xls_1 = pd.read_excel("ST+上市公司交易额表.xls")
data_xls_2 = pd.read_excel("ST+上市公司营收1.xls")
data_xls_3 = pd.read_excel("ST+财务比率.xls")
# data_xls_1 = pd.read_excel("餐饮1.xls")
# data_xls_2 = pd.read_excel("餐饮2.xls")
# data_xls_3 = pd.read_excel("餐饮4.xls")
# data_xls_1 = pd.read_excel("水利1.xls")
# data_xls_2 = pd.read_excel("水利2.xls")
# data_xls_3 = pd.read_excel("水利3.xls")
# data_xls_1 = pd.read_excel("交通_Q3_1.xls")
# data_xls_2 = pd.read_excel("交通_Q3_2.xls")
# data_xls_3 = pd.read_excel("交通_Q3_3.xls")

"""
Z计分模型的判别函数如下:
      Z =0.012X1+0.014X2+0.033X3+0.006X4+0.999X5
 2.Z计分模型应用分析的前期准备
    Z计分模型主要用于预测企业财务失败或破产的可能性，也可用于判定企业经营的状况，是目前在财务分析中最常用的一种模型，故本文首先用z计分模型来进行判别分析。先根据z计分模型分别计算三家乳品企业的z值，再按z值对企业进行比较和分析。
其中：
    X1=营运资金/资产总额=(流动资产一流动负债)/资产总额
    该比率反映企业资产的流动性和分布状况，比率越高说明资产的流动性越强，财务失败的可能越小：
    X2=留存收益/资产总额=(股东权益一股本一资本公积)/资产总额
    该比率反映企业的积累水平，比率越高说明企业的积累水平越高，财务失败的可能越小：
    X3=息税前利润/资产总额=(利润总额+利息费用)/资产总额
    该比率反映企业的获利水平，比率越高说明企业的获利能力越强，财务失败的可能越小：
    X4=股东权益市价/负债总额=（非流通股总股数+流通股）*每股市价/负债总额
    该比率反映企业所有者权益(或净产)与企业债务之间的关系，比率越高，说明企业所有者权益越高或净资产越高，企业财务失败的可能性就越小
    X5=营业收入/资产总额：
    该比率反映企业总资产的周转速度或营运能力，比率越高说明企业的资产利用率越高，效果也越好。
    （X3中的利息费用无法直接从年报中获取，故以财务费用代替，对结果应无实质性影响;X4中的每股市价以股票当年股市收盘价计算。）
"""


class Z_score:

    def __init__(self, filepath_1, filepath_2, filepath_3):
        """
        构造函数
        """
        self.filepath_1 = filepath_1
        self.filepath_2 = filepath_2
        self.filepath_3 = filepath_3
        


    def Z_count(self, X):
        """
            功能：计算Z值并返回
        """
        # Z = 0.012 * X[0] + 0.014 * X[1] + 0.033 * X[2] + 0.006 * X[3] + 0.999 * X[4]
        # print("Z_X:", X)
        Z = 0.065 * X[0] + 0.326 * X[1] + 0.01 * X[2] + 0.067 * X[3]
        return Z

    def read_data(self):
        """
            功能：读取数据
        """

        # 读取上市公司数据
        data_1 = data_xls_1.ix[:,
                 ["上市状态_Listedstate"]].values

        # print("data_1", data_1)
        data_2 = data_xls_2.ix[:,
                 ['流动负债合计(元)_Totcurlia', '负债合计(元)_Totlia', '盈余公积(元)_Surres',
                  '流动资产合计(元)_Totcurass', '资产总计(元)_Totass', "最新公司全称_Lcomnm", "未分配利润(元)_Retear"]].values

        data_3 = data_xls_3.ix[:,
                 ['息税前利润_EBIT', '股票市值/总负债(Ⅰ)_MarkValtotdb1']].values

        # print("data_2", data_2)
        # print(data_2)
        # print(data_3)
        """
        资本公积(元)_Capsur
        所有者权益合计(元)_TotSHE
        利润总额(元)_Totalprf
        财务费用(元)_Finexp
        实收资本(或股本)(元)_Shrcap
        """

        # 公司数据

        # 公司年份数量
        self.com_num = 3
        # 上市状态_Listedstate
        self.State_list = data_1[:, 0]
        # State_list

        # 流动负债合计(元)_Totcurlia
        self.SD_list = data_2[:, 0]
        # print(SD_li)
        # 负债合计(元)_TotLia
        self.D_list = data_2[:, 1]
        # 盈余公积(元)_Surres
        self.Surres_list = data_2[:, 2]
        # print("D_list：", D_list)
        # 流动资产合计(元)_Totcurass
        self.Totcurass_list = data_2[:, 3]
        # 资产总计(元)_Totass
        self.Totass_list = data_2[:, 4]
        # 最新公司全称_Lcomnm
        self.Lconnm_list = list(data_2[:, 5][::com_num])
        # Lconnm_list.replace("*ST", "ST", inplace=1)
        # len(Lconnm_list)
        # 未分配利润(元)_Retear
        self.Retear_list = data_2[:, 6]
        # 息税前利润_EBIT
        self.EBIT_list = data_3[:, 0]
        # 股票市值/总负债(Ⅰ)_MarkValtotdb1
        self.MarkValtotdb1_list = data_3[:, 1]

    def X_count(self, i):
        """
            功能：计算x1~x5的值
            Z=0.065×Xl+0.326×X2+0.01×X3+0.067×X4
            其中：X1= (营运资产 / 总资产)×100
            X2= 留存收益 / 总资产 = (盈余公积 + 未分配利润)/总资产×100
            X3=税息前利润 / 总资产×100
            X4= 资本市值 / 总负债×100
        """
        x1 = (self.Retear_list[i] - self.SD_list[i]) / self.Totass_list[i] * 100
        x2 = (self.EBIT_list[i] + self.Surres_list[i]) / self.Totass_list[i] * 100
        x3 = self.EBIT_list[i] / self.Totass_list[i] * 100
        x4 = self.MarkValtotdb1_list[i] * 100
        # print("[x1, x2, x3, x4", [x1, x2, x3, x4])
        return [x1, x2, x3, x4]


"""
Z<2.675，借款被划入违约组；
反之，如果Z≥2.675，则借款人被划入非违约组。
当1.81<Z<2.99阿尔特曼发现此时的判断失误比较大，称该重叠区域为未知区Ez
"""


def main():
    """
        主函数
    """
    Company_name = Lconnm_list

    Z_list = []
    number = 0

    for i in range(int(data_1.shape[0])):
        X = X_count(i)
        Z = Z_count(X)

        Z_list.append(Z)
        Z_list_length = len(Z_list)

        # print("Z_list_length = {}".format(Z_list_length))
        # print("i = {}".format(i))

        # print("Z_list = {}".format(Z_list[i - 2: i]))
        #
        # if Z_list_length % com_num == 0 and Z_list_length != 0:
        #     # print("Z_list", Z_list)
        #     plt_tle = Company_name[number] + "16年到18年Z值统计"
        #     height_list = Z_list[i - 2: i + 1]
        #     # 绘制条形图
        #     rects1 = plt.bar(x=range(1, 6, 2), height=height_list, width=1, alpha=0.8, color='red')
        #     # plt.ylim(0, 1)  # y轴取值范围
        #     # 设置x轴坐标点显示
        #     tick_labels = ["2016", "2017", "2018"]
        #     # tick_labels = ["2016", "2017"]
        #     tick_pos = np.arange(1, 7, 2)
        #     plt.xticks(tick_pos, tick_labels)
        #     plt.title(plt_tle, size=16)
        #     plt.xlabel("年份", size=10)
        #     plt.ylabel("Z值", size=10)
        #     # plt.legend()     # 设置题注
        #
        #     for a, b in zip(tick_pos, height_list):
        #         plt.text(a, b + 0.002, '%.4f' % b, ha='center', va='bottom', fontsize=10)
        #
        #     plt.show()
        #     # Z列表初始化
        #     # Z_list = []
        #     number += 1

    dleta = [100] * len(Z_list)
    # map()函数映射求两个列表相乘

    # func = lambda x, y: x * y
    # result = map(func, Z_list, dleta)
    # Z_list_result = list(result)
    # print(Z_list_result)

    print("Z_list = {}".format(Z_list))
    predict_list = []
    error_num = 0
    correct_num = 0
    grey_num = 0
    for i in range(len(Z_list)):
        if Z_list[i] >= 1.23:
            predict_list.append("Norm")
        elif Z_list[i] < 1.23:
            predict_list.append("ST")

    print("State_list = {}".format(State_list))
    for i in range(len(predict_list)):
        if predict_list[i] == State_list[i]:
            correct_num += 1
        else:
            error_num += 1

    print("predict_list = {}".format(predict_list))
    plt_tle = "预测结果"
    height_list = [correct_num, error_num]
    # 绘制条形图
    rects1 = plt.bar(x=range(0, 3, 2), height=height_list, width=1, alpha=0.8, color='red')
    # plt.ylim(0, 1)  # y轴取值范围
    # 设置x轴坐标点显示
    tick_labels = ["correct_num", "error_num"]
    tick_pos = np.arange(0, 3, 2)
    plt.xticks(tick_pos, tick_labels)
    plt.title(plt_tle, size=16)
    plt.xlabel("结果", size=10)
    plt.ylabel("计数", size=10)
    # plt.legend()     # 设置题注

    for a, b in zip(tick_pos, height_list):
        plt.text(a, b + 0.02, '%.4f' % b, ha='center', va='bottom', fontsize=10)

    plt.show()


if __name__ == '__main__':
    main()

"""
Z<2.675，借款被划入违约组；
反之，如果Z≥2.675，则借款人被划入非违约组。
当1.81<Z<2.99阿尔特曼发现此时的判断失误比较大，称该重叠区域为未知区
"""
